package com.zt.student.service.impl;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.zt.common.common.ApiException;
import com.zt.common.common.CodeMsg;
import com.zt.common.pojo.StudentVx;
import com.zt.common.pojo.netty.Sender;
import com.zt.common.pojo.origin.OriginStudent;
import com.zt.common.utils.JwtUtil;
import com.zt.common.utils.RedisUtil;
import com.zt.common.utils.WechatUtil;
import com.zt.student.dao.StudentDao;
import com.zt.student.dto.StudentDTO;
import com.zt.student.pojo.WechatLoginCheck;
import com.zt.student.pojo.WechatToken;
import com.zt.student.service.OriginStudentService;
import com.zt.student.service.StudentService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;

/**
 * description:
 * author:zt
 * date:2021-11-26
 */
@Service
@Transactional
public class StudentServiceImpl implements StudentService {

    private static final Log log = LogFactory.get();

    @Autowired
    private StudentDao studentDao;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private OriginStudentService originStudentService;

    @Override
    public StudentVx handleLogin(String code, String rawData, String signature, HttpServletRequest request) {

        // 2.开发者服务器 登录凭证校验接口 appid + appsecret + code
        JSONObject sessionKeyOpenId = WechatUtil.getSessionKeyOrOpenId(code);
        // 3.接收微信接口服务 获取返回的参数
        String openid = sessionKeyOpenId.getString("openid");

        String sessionKey = sessionKeyOpenId.getString("session_key");


        Subject subject = SecurityUtils.getSubject();
        //构造 交给shiro验证的wechatToken
        WechatLoginCheck wechat = new WechatLoginCheck();
        wechat.setSignature(signature).setRawData(rawData).setSessionKey(sessionKey);

        WechatToken token = new WechatToken(wechat);
        //交给shiro wechatRealm进行认证
        try {
            subject.login(token);
        }catch (AuthenticationException e){
            throw new ApiException(CodeMsg.VERIFY_ERROR);
        }

        StudentVx student = getStudentByOpenId(openid);

        JSONObject rawDataJson = JSON.parseObject(rawData);
        if (student == null) {
            log.info("openId：" + openid + "首次登录");
            //用户不存在，存入用户信息
            String nickName = rawDataJson.getString("nickName");
            String avatarUrl = rawDataJson.getString("avatarUrl");
            String gender = rawDataJson.getString("gender");
            String city = rawDataJson.getString("city");
            String country = rawDataJson.getString("country");
            String province = rawDataJson.getString("province");

            student = new StudentVx();
            student.setOpenId(openid);
            student.setCreateTime(new Date());
            student.setLastLogin(new Date());
            student.setSessionKey(sessionKey);
            student.setCity(city);
            student.setProvince(province);
            student.setCountry(country);
            student.setAvatar(avatarUrl);
            student.setGender(Integer.parseInt(gender));
            student.setNickname(nickName);
            studentDao.insert(student);
        } else {
            log.info("openId：" + openid + "更新登录时间");
            // 已存在，更新用户登录时间
            student.setLastLogin(new Date());
            studentDao.update(student);
        }

        log.info(student + "登录成功");

        return student;
    }

    @Override
    public StudentVx getStudentByStuId(String studentId){
        return studentDao.selectStudentByStuId(studentId);
    }

    @Override
    public StudentVx getStudentByOpenId(String openId){
        return studentDao.selectStudentByOpenId(openId);
    }

    /**
     * 绑定studentVx与originStudent 需要校验originStudent身份
     * @param studentDTO originStudent与关联openId的randomKey
     */
    @Override
    public String update(StudentDTO studentDTO,HttpServletResponse response) {
        String studentId = studentDTO.getStudentId();
        String randomKey = studentDTO.getRandomKey();

        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(studentId, studentDTO.getPassword());

        try {
            log.info("正在校验：" + studentId);
            subject.login(token);
        }catch (UnknownAccountException ue){
            throw new ApiException(CodeMsg.USER_NOT_FOUND);
        }catch (IncorrectCredentialsException ie){
            throw new ApiException(CodeMsg.WRONG_PASSWORD);
        }

        log.info("校验成功");

        StudentVx studentByStuId = getStudentByStuId(studentId);
        if (studentByStuId != null)
            //该学号已绑定微信
            throw new ApiException(CodeMsg.STUDENT_ID_HAS_BIND);

        String openId = String.valueOf(redisUtil.get(randomKey));
        StudentVx student = studentDao.selectStudentByOpenId(openId);
        //绑定studentVx
        student.setStudentId(studentId);

        studentDao.update(student);
        //更新完毕 删除randomKey与openId的关联关系
        redisUtil.del(randomKey);

        String reToken = JwtUtil.getToken(studentId, String.valueOf(System.currentTimeMillis()), 0);

        response.setHeader("Authorization", reToken);
        response.setHeader("access-Control-Expose-Headers", "Authorization");

        OriginStudent originStudent = originStudentService.getOriginStuById(studentId);
        return JSON.toJSONString(new Sender(studentId, originStudent.getStudentName(),student.getAvatar()));
    }

    @Override
    public void logOut(HttpServletRequest request){
        String studentId = JwtUtil.decodedGetID(request.getHeader("Authorization"));
        if (redisUtil.hasKey(studentId)){
            redisUtil.del(studentId);
        }
        log.info(studentId + "退出登录");
    }

    @Override
    public void cancelBindStuId(HttpServletRequest request){
        String studentId = JwtUtil.decodedGetID(request.getHeader("Authorization"));
        StudentVx student = getStudentByStuId(studentId);
        if (student != null) {
            student.setStudentId(null);
            studentDao.cancelBindStuId(student.getOpenId());
        }
        //取消绑定学号后自动退出登录
        logOut(request);
    }

    /**
     * 学生上传头像
     */
    @Override
    public String updateAvatar(MultipartFile file,HttpServletRequest request) throws IOException {
        String studentId = JwtUtil.decodedGetID(request.getHeader("Authorization"));
//        String studentId = "20181002970";

        if (file==null) throw new ApiException(CodeMsg.RESOURCE_FORMAT_NOT_MATCH);
        //允许上传的文件后缀名
        List<String> list = Lists.newArrayList("jpg","jpeg","png");

        String fileName = file.getOriginalFilename();
        log.info(fileName);
        //文件后缀名
        String extendName = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
        if (!list.contains(extendName)) throw new ApiException(CodeMsg.RESOURCE_FORMAT_NOT_MATCH);

        String filePath = "/root/upload/";

        String realName = System.currentTimeMillis() + "-" + fileName;
        File file1 = new File(filePath, realName);
        file.transferTo(file1);

        //修改数据库头像信息
        StudentVx student = studentDao.selectStudentByStuId(studentId);
        String avatarUrl = "https://murielndzt.top/upload/" + realName;
        student.setAvatar(avatarUrl);
        studentDao.update(student);

        return avatarUrl;
    }
}
